package com.shrct.businessprocess.budget.impl;

import com.google.common.base.Objects;
import com.shrct.businessprocess.budget.BudgetType;
import com.shrct.businessprocess.budget.BudgetTypeManager;
import com.shrct.businessprocess.budget.RCBudget;
import com.shrct.businessprocess.budget.RCBudgetCategory;
import com.shrct.businessprocess.budget.RCBudgetDivision;
import com.shrct.businessprocess.budget.RCBudgetTaskStatus;
import com.shrct.businessprocess.budget.RCCost4RemainItem;
import com.shrct.businessprocess.budget.RCCostBreakDown;
import com.shrct.businessprocess.budget.impl.RCCostBreakDownImpl;
import com.shrct.businessprocess.budget.proxy.RCBudgetProxy;
import com.shrct.businessprocess.common.CurrencyType;
import com.shrct.businessprocess.diagnose.DiagnoseItem;
import com.shrct.businessprocess.diagnose.IDiagnoseAcceptor;
import com.shrct.businessprocess.money.Moneys;
import com.shrct.businessprocess.project.RCExchangeRate;
import com.shrct.businessprocess.project.RCProject;
import com.shrct.businessprocess.project.RCProjectMoney;
import com.shrct.businessprocess.project.RCRealMoney;
import com.shrct.businessprocess.purchase.RCBudgetContract;
import com.shrct.businessprocess.purchase.RCPay;
import com.shrct.businessprocess.purchase.RCPayRequest;
import com.shrct.businessprocess.purchase.impl.RCBudgetContractImpl;
import edu.fudan.mylang.common.NumberExtensions;
import edu.fudan.mylang.pf.BaseModelObject;
import edu.fudan.mylang.pf.IGenericQuery;
import java.util.ArrayList;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
import org.eclipse.xtext.xbase.lib.DoubleExtensions;
import org.eclipse.xtext.xbase.lib.Functions.Function1;
import org.eclipse.xtext.xbase.lib.Functions.Function2;
import org.eclipse.xtext.xbase.lib.IterableExtensions;
import org.eclipse.xtext.xbase.lib.ObjectExtensions;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.hibernate.annotations.DiscriminatorOptions;
import org.springframework.beans.factory.BeanFactory;

@Entity
@DiscriminatorValue("RCBUDGET_TYPE")
@DiscriminatorOptions(force = true)
@DiscriminatorColumn(length = 64)
@Table(name = "rcbudget")
public abstract class RCBudgetImpl extends BaseModelObject implements RCBudget {
  public RCBudgetImpl() {
    super();
  }
  
  public RCBudgetImpl(final RCCostBreakDown cbd) {
    super();
    this.cbd = cbd;
  }
  
  @JoinColumn(name = "cbd_id")
  @ManyToOne(targetEntity = RCCostBreakDownImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST })
  private RCCostBreakDown cbd;
  
  public RCCostBreakDown getCbd() {
    return this.cbd;
  }
  
  public RCBudget setCbd(final RCCostBreakDown cbd) {
    this.cbd = cbd;
    return this;			
    
  }
  
  private String comment;
  
  public String getComment() {
    return this.comment;
  }
  
  public RCBudget setComment(final String comment) {
    this.comment = comment;
    return this;			
    
  }
  
  @OneToMany(targetEntity = RCBudgetContractImpl.class, cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, mappedBy = "budget")
  private Collection<RCBudgetContract> contracts = new java.util.ArrayList<com.shrct.businessprocess.purchase.RCBudgetContract>();;
  
  public Collection<RCBudgetContract> getContracts() {
    return this.contracts;
  }
  
  public RCBudgetContract createAndAddtoContracts() {
    getContracts().size();
    com.shrct.businessprocess.purchase.RCBudgetContract rCBudgetContract = new com.shrct.businessprocess.purchase.impl.RCBudgetContractImpl(this);
    getObjectFactory().create(rCBudgetContract);
    getContracts().add(rCBudgetContract);
    return rCBudgetContract;
    
  }
  
  public RCBudgetContract createAndAddtoContracts(final Procedure1<RCBudgetContract> updater) {
    getContracts().size();
    com.shrct.businessprocess.purchase.RCBudgetContract rCBudgetContract = new com.shrct.businessprocess.purchase.impl.RCBudgetContractImpl(this);
    getObjectFactory().create(rCBudgetContract);
    getContracts().add(rCBudgetContract);
    return rCBudgetContract;
    
  }
  
  public RCBudget removeAllContracts() {
    for(RCBudgetContract obj : this.contracts){
    	getObjectFactory().delete(obj);
    }
    this.contracts.clear();
    return this;	
    
  }
  
  public RCBudget removeFromContracts(final RCBudgetContract rCBudgetContract) {
    this.contracts.remove(rCBudgetContract);
    getObjectFactory().delete(rCBudgetContract);
    return this;
    
  }
  
  public String getEntityName() {
    BudgetType _budgetType = this.getBudgetType();
    String _name = _budgetType.getName();
    return _name;
  }
  
  public RCBudgetCategory getCategory() {
    BudgetType _budgetType = this.getBudgetType();
    RCBudgetCategory _budgetCategory = _budgetType.getBudgetCategory();
    return _budgetCategory;
  }
  
  public Double getRemainAmount() {
    RCProjectMoney _netPrice = this.getNetPrice();
    Double _hostAmount = _netPrice.toHostAmount();
    RCProjectMoney _actualCostAmount = this.getActualCostAmount();
    Double _hostAmount_1 = _actualCostAmount.toHostAmount();
    double _minus = DoubleExtensions.operator_minus(_hostAmount, _hostAmount_1);
    return Double.valueOf(_minus);
  }
  
  public String getSortKey() {
    String _typeId = this.getTypeId();
    return _typeId;
  }
  
  public BudgetType getBudgetType() {
    BeanFactory _beanFactory = this.getBeanFactory();
    BudgetTypeManager _bean = _beanFactory.<BudgetTypeManager>getBean(BudgetTypeManager.class);
    String _typeId = this.getTypeId();
    BudgetType _budgetType = _bean.getBudgetType(_typeId);
    return _budgetType;
  }
  
  public Collection<RCBudgetDivision> getBudgetDivisions() {
    ArrayList<RCBudgetDivision> _newArrayList = CollectionLiterals.<RCBudgetDivision>newArrayList();
    return _newArrayList;
  }
  
  /**
   * 毛利率,可能为0(0的意义是什么?)
   */
  public Double getGrossProfit() {
    double _xifexpression = (double) 0;
    RCProjectMoney _contractPrice = this.getContractPrice();
    Double _amount = _contractPrice.getAmount();
    boolean _equals = ((_amount).doubleValue() == 0);
    if (_equals) {
      return Double.valueOf(0d);
    } else {
      RCProjectMoney _contractPrice_1 = this.getContractPrice();
      Double _hostAmount = _contractPrice_1.toHostAmount();
      RCProjectMoney _netPrice = this.getNetPrice();
      Double _hostAmount_1 = _netPrice.toHostAmount();
      double _minus = DoubleExtensions.operator_minus(_hostAmount, _hostAmount_1);
      RCProjectMoney _contractPrice_2 = this.getContractPrice();
      Double _hostAmount_2 = _contractPrice_2.toHostAmount();
      double _divide = (_minus / (_hostAmount_2).doubleValue());
      _xifexpression = _divide;
    }
    return Double.valueOf(_xifexpression);
  }
  
  /**
   * 根据实际合同计算的销售净价
   */
  public RCProjectMoney getActualContractPrice() {
    RCProjectMoney _xifexpression = null;
    RCProject _project = this.cbd.getProject();
    Boolean _allContractCollected = _project.getAllContractCollected();
    if ((_allContractCollected).booleanValue()) {
      final Function1<RCBudgetContract,RCProjectMoney> _function = new Function1<RCBudgetContract,RCProjectMoney>() {
          public RCProjectMoney apply(final RCBudgetContract it) {
            RCProjectMoney _amount = it.getAmount();
            return _amount;
          }
        };
      Iterable<RCProjectMoney> _map = IterableExtensions.<RCBudgetContract, RCProjectMoney>map(this.contracts, _function);
      RCProject _project_1 = this.cbd.getProject();
      RCExchangeRate _defaultExchangeRate = _project_1.getDefaultExchangeRate();
      RCProjectMoney _sum = Moneys.sum(_map, _defaultExchangeRate);
      _xifexpression = _sum;
    } else {
      RCProjectMoney _contractPrice = this.getContractPrice();
      _xifexpression = _contractPrice;
    }
    return _xifexpression;
  }
  
  /**
   * 根据实际合同计算的毛利率
   */
  public Double getActualGrossProfit() {
    double _xblockexpression = (double) 0;
    {
      final RCProjectMoney actualContractPrice = this.getActualContractPrice();
      double _xifexpression = (double) 0;
      Double _amount = actualContractPrice.getAmount();
      boolean _equals = ((_amount).doubleValue() == 0);
      if (_equals) {
        return Double.valueOf(0d);
      } else {
        Double _hostAmount = actualContractPrice.toHostAmount();
        RCProjectMoney _netPrice = this.getNetPrice();
        Double _hostAmount_1 = _netPrice.toHostAmount();
        double _minus = DoubleExtensions.operator_minus(_hostAmount, _hostAmount_1);
        Double _hostAmount_2 = actualContractPrice.toHostAmount();
        double _divide = (_minus / (_hostAmount_2).doubleValue());
        _xifexpression = _divide;
      }
      _xblockexpression = (_xifexpression);
    }
    return Double.valueOf(_xblockexpression);
  }
  
  public Collection<? extends RCPayRequest> getAllPayRequests() {
    ArrayList<RCPayRequest> _newArrayList = CollectionLiterals.<RCPayRequest>newArrayList();
    return _newArrayList;
  }
  
  public Collection<RCPay> getAllPays() {
    IGenericQuery<RCPay> query=getObjectFactory().createGenericQuery(RCPay.class,"select pay from com.shrct.businessprocess.purchase.impl.RCPayImpl as pay   where ((pay.budget) = (:this)) and  pay.active = 1      ").setParameter("this",this);
    Collection<RCPay> _list = query.list();
    return _list;
  }
  
  public RCRealMoney getTotalPaiedAmount() {
    RCRealMoney _rCRealMoney = new RCRealMoney();
    final Procedure1<RCRealMoney> _function = new Procedure1<RCRealMoney>() {
        public void apply(final RCRealMoney it) {
          RCProject _project = RCBudgetImpl.this.cbd.getProject();
          RCExchangeRate de = _project.getDefaultExchangeRate();
          it.setAmount(Double.valueOf(0d));
          CurrencyType _currencyType = de.getCurrencyType();
          it.setCurrencyType(_currencyType);
          it.setExchangeRate(Double.valueOf(1d));
        }
      };
    RCRealMoney _doubleArrow = ObjectExtensions.<RCRealMoney>operator_doubleArrow(_rCRealMoney, _function);
    return _doubleArrow;
  }
  
  public RCProjectMoney getTotalPayRequestedAmount() {
    RCProjectMoney _rCProjectMoney = new RCProjectMoney();
    final Procedure1<RCProjectMoney> _function = new Procedure1<RCProjectMoney>() {
        public void apply(final RCProjectMoney it) {
          it.setAmount(Double.valueOf(0d));
          RCProject _project = RCBudgetImpl.this.cbd.getProject();
          RCExchangeRate _defaultExchangeRate = _project.getDefaultExchangeRate();
          it.setExchange(_defaultExchangeRate);
        }
      };
    RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_rCProjectMoney, _function);
    return _doubleArrow;
  }
  
  /**
   * 计算合同总金额
   */
  public RCProjectMoney getTotalRequiredAmount() {
    RCProjectMoney _xblockexpression = null;
    {
      final Function1<RCBudgetContract,RCProjectMoney> _function = new Function1<RCBudgetContract,RCProjectMoney>() {
          public RCProjectMoney apply(final RCBudgetContract it) {
            RCProjectMoney _totalAmount = it.getTotalAmount();
            return _totalAmount;
          }
        };
      Iterable<RCProjectMoney> _map = IterableExtensions.<RCBudgetContract, RCProjectMoney>map(this.contracts, _function);
      final Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney> _function_1 = new Function2<RCProjectMoney,RCProjectMoney,RCProjectMoney>() {
          public RCProjectMoney apply(final RCProjectMoney m1, final RCProjectMoney m2) {
            RCProjectMoney _plus = m1.plus(m2);
            return _plus;
          }
        };
      RCProjectMoney result = IterableExtensions.<RCProjectMoney>reduce(_map, _function_1);
      RCProjectMoney _xifexpression = null;
      boolean _equals = Objects.equal(result, null);
      if (_equals) {
        RCProjectMoney _rCProjectMoney = new RCProjectMoney();
        final Procedure1<RCProjectMoney> _function_2 = new Procedure1<RCProjectMoney>() {
            public void apply(final RCProjectMoney it) {
              it.setAmount(Double.valueOf(0d));
              RCExchangeRate _defaultContractExchangeRate = RCBudgetImpl.this.getDefaultContractExchangeRate();
              it.setExchange(_defaultContractExchangeRate);
            }
          };
        RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_rCProjectMoney, _function_2);
        _xifexpression = _doubleArrow;
      } else {
        RCExchangeRate _defaultContractExchangeRate = this.getDefaultContractExchangeRate();
        RCProjectMoney _money = result.toMoney(_defaultContractExchangeRate);
        _xifexpression = _money;
      }
      _xblockexpression = (_xifexpression);
    }
    return _xblockexpression;
  }
  
  public Iterable<RCCost4RemainItem> getRCCost4RemainItems() {
    Iterable<RCCost4RemainItem> _xblockexpression = null;
    {
      Boolean _seemsFinished = this.seemsFinished();
      if ((_seemsFinished).booleanValue()) {
        return CollectionLiterals.<RCCost4RemainItem>newArrayList();
      }
      RCCost4RemainItem _rCCost4RemainItem = new RCCost4RemainItem();
      final Procedure1<RCCost4RemainItem> _function = new Procedure1<RCCost4RemainItem>() {
          public void apply(final RCCost4RemainItem it) {
            it.setBudget(RCBudgetImpl.this);
            String _entityName = RCBudgetImpl.this.getEntityName();
            it.setTitle(_entityName);
            Double _remainAmount = RCBudgetImpl.this.getRemainAmount();
            it.setAmount(_remainAmount);
            Double _netTaxRate = RCBudgetImpl.this.getNetTaxRate();
            it.setTaxRate(_netTaxRate);
          }
        };
      RCCost4RemainItem _doubleArrow = ObjectExtensions.<RCCost4RemainItem>operator_doubleArrow(_rCCost4RemainItem, _function);
      ArrayList<RCCost4RemainItem> _newArrayList = CollectionLiterals.<RCCost4RemainItem>newArrayList(_doubleArrow);
      final Function1<RCCost4RemainItem,Boolean> _function_1 = new Function1<RCCost4RemainItem,Boolean>() {
          public Boolean apply(final RCCost4RemainItem it) {
            Double _amount = it.getAmount();
            boolean _greaterThan = ((_amount).doubleValue() > 0);
            return Boolean.valueOf(_greaterThan);
          }
        };
      Iterable<RCCost4RemainItem> _filter = IterableExtensions.<RCCost4RemainItem>filter(_newArrayList, _function_1);
      _xblockexpression = (_filter);
    }
    return _xblockexpression;
  }
  
  /**
   * 在此预算项目上的已发生成本
   */
  public RCProjectMoney getActualCostAmount() {
    RCProject _project = this.cbd.getProject();
    RCExchangeRate _defaultExchangeRate = _project.getDefaultExchangeRate();
    RCProjectMoney _zeroAmount = this.getZeroAmount(_defaultExchangeRate);
    return _zeroAmount;
  }
  
  /**
   * 判断该预算项目作为任务计划是否已经执行完毕
   */
  public Boolean seemsFinished() {
    return Boolean.valueOf(false);
  }
  
  public RCBudgetTaskStatus getBudgetTaskStatus() {
    return RCBudgetTaskStatus.meaningless;
  }
  
  /**
   * 判断该预算项目在计算ActualCost时，应该使用实际支出还是预算支出
   */
  public boolean shouldUseRealActualCost() {
    boolean _or = false;
    Boolean _seemsFinished = this.seemsFinished();
    if ((_seemsFinished).booleanValue()) {
      _or = true;
    } else {
      RCProjectMoney _actualCostAmount = this.getActualCostAmount();
      Double _hostAmount = _actualCostAmount.toHostAmount();
      RCProjectMoney _netPrice = this.getNetPrice();
      Double _hostAmount_1 = _netPrice.toHostAmount();
      boolean _greaterThan = (_hostAmount.compareTo(_hostAmount_1) > 0);
      _or = ((_seemsFinished).booleanValue() || _greaterThan);
    }
    return _or;
  }
  
  /**
   * 获取到当前为止该项目的预期总开销
   */
  public RCProjectMoney getExpectedCostAmount(final Double percent) {
    RCProjectMoney _xblockexpression = null;
    {
      Double _xifexpression = null;
      boolean _shouldUseRealActualCost = this.shouldUseRealActualCost();
      if (_shouldUseRealActualCost) {
        RCProjectMoney _actualCostAmount = this.getActualCostAmount();
        Double _hostAmount = _actualCostAmount.toHostAmount();
        _xifexpression = _hostAmount;
      } else {
        RCProjectMoney _netPrice = this.getNetPrice();
        Double _hostAmount_1 = _netPrice.toHostAmount();
        _xifexpression = _hostAmount_1;
      }
      final Double logicCost = _xifexpression;
      RCProject _project = this.cbd.getProject();
      RCExchangeRate _defaultExchangeRate = _project.getDefaultExchangeRate();
      RCProjectMoney _zeroAmount = this.getZeroAmount(_defaultExchangeRate);
      final Procedure1<RCProjectMoney> _function = new Procedure1<RCProjectMoney>() {
          public void apply(final RCProjectMoney it) {
            it.setAmount(logicCost);
          }
        };
      RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_zeroAmount, _function);
      RCProjectMoney _multi = _doubleArrow.multi(percent);
      _xblockexpression = (_multi);
    }
    return _xblockexpression;
  }
  
  public RCExchangeRate getDefaultContractExchangeRate() {
    RCProjectMoney _contractPrice = this.getContractPrice();
    RCExchangeRate _exchange = _contractPrice.getExchange();
    return _exchange;
  }
  
  public RCProjectMoney getZeroAmount(final RCExchangeRate exchangeRage) {
    RCProjectMoney _rCProjectMoney = new RCProjectMoney();
    final Procedure1<RCProjectMoney> _function = new Procedure1<RCProjectMoney>() {
        public void apply(final RCProjectMoney it) {
          it.setAmount(Double.valueOf(0d));
          it.setExchange(exchangeRage);
        }
      };
    RCProjectMoney _doubleArrow = ObjectExtensions.<RCProjectMoney>operator_doubleArrow(_rCProjectMoney, _function);
    return _doubleArrow;
  }
  
  public void diagnose(final IDiagnoseAcceptor acceptor) {
    RCRealMoney _totalPaiedAmount = this.getTotalPaiedAmount();
    Double _hostAmount = _totalPaiedAmount.toHostAmount();
    RCProjectMoney _netPrice = this.getNetPrice();
    Double _hostAmount_1 = _netPrice.toHostAmount();
    boolean _greaterThan = (_hostAmount.compareTo(_hostAmount_1) > 0);
    if (_greaterThan) {
      DiagnoseItem _diagnoseItem = new DiagnoseItem();
      final Procedure1<DiagnoseItem> _function = new Procedure1<DiagnoseItem>() {
          public void apply(final DiagnoseItem it) {
            String _entityName = RCBudgetImpl.this.getEntityName();
            String _plus = ("\u9884\u7B97\u9879[" + _entityName);
            String _plus_1 = (_plus + "]:\u652F\u51FA\u8D85\u51FA\u9884\u7B97");
            it.setMessage(_plus_1);
          }
        };
      DiagnoseItem _doubleArrow = ObjectExtensions.<DiagnoseItem>operator_doubleArrow(_diagnoseItem, _function);
      acceptor.accept(_doubleArrow);
    }
  }
  
  /**
   * 获取累计进项税
   */
  public RCProjectMoney getContractInvoiceTax() {
    RCProjectMoney _contractPrice = this.getContractPrice();
    Double _contractTaxRate = this.getContractTaxRate();
    Double _nullsafe = NumberExtensions.nullsafe(_contractTaxRate);
    double _divide = ((_nullsafe).doubleValue() / 100);
    double _plus = (1 + _divide);
    RCProjectMoney _div = _contractPrice.div(Double.valueOf(_plus));
    Double _contractTaxRate_1 = this.getContractTaxRate();
    double _divide_1 = ((_contractTaxRate_1).doubleValue() / 100);
    RCProjectMoney _multi = _div.multi(Double.valueOf(_divide_1));
    return _multi;
  }
  
  public RCProjectMoney getNetInvoiceTax() {
    RCProjectMoney _netPrice = this.getNetPrice();
    Double _netTaxRate = this.getNetTaxRate();
    double _divide = ((_netTaxRate).doubleValue() / 100);
    double _plus = (1 + _divide);
    RCProjectMoney _div = _netPrice.div(Double.valueOf(_plus));
    Double _netTaxRate_1 = this.getNetTaxRate();
    double _divide_1 = ((_netTaxRate_1).doubleValue() / 100);
    RCProjectMoney _multi = _div.multi(Double.valueOf(_divide_1));
    return _multi;
  }
  
  /**
   * 销售发票税
   */
  public RCProjectMoney getInvoiceTax() {
    RCProjectMoney _contractInvoiceTax = this.getContractInvoiceTax();
    RCProjectMoney _netInvoiceTax = this.getNetInvoiceTax();
    RCProjectMoney _substract = _contractInvoiceTax.substract(_netInvoiceTax);
    return _substract;
  }
  
  public RCBudgetProxy toProxy() {
    com.shrct.businessprocess.budget.proxy.RCBudgetProxy proxy = new com.shrct.businessprocess.budget.proxy.RCBudgetProxy();
    proxy.setId(this.getId());
    if(this instanceof edu.fudan.mylang.pf.INamedModelObject){
    	proxy.setName(((edu.fudan.mylang.pf.INamedModelObject)this).getEntityName());
    }
    return proxy;
    
  }
}
